﻿/******************************************************************************
 * SunnyUI 开源控件库、工具类库、扩展类库、多页面开发框架。
 * CopyRight (C) 2012-2021 ShenYongHua(沈永华).
 * QQ群：56829229 QQ：17612584 EMail：SunnyUI@QQ.Com
 *
 * Blog:   https://www.cnblogs.com/yhuse
 * Gitee:  https://gitee.com/yhuse/SunnyUI
 * GitHub: https://github.com/yhuse/SunnyUI
 *
 * SunnyUI.Common.dll can be used for free under the MIT license.
 * If you use this code, please keep this note.
 * 如果您使用此代码，请保留此说明。
 ******************************************************************************
 * 文件名称: UCollections.cs
 * 文件说明: 集合扩展类
 * 当前版本: V3.0
 * 创建日期: 2020-01-01
 *
 * 2020-01-01: V2.2.0 增加文件说明
******************************************************************************/

using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Reflection;

namespace Sunny.UI
{
    /// <summary>
    /// Collections 扩展类
    /// </summary>
    public static class CollectionsEx
    {
        public static List<T> ToList<T>(this ArrayList arrayList)
        {
            return arrayList.OfType<T>().ToList();
        }

        //https://www.codeproject.com/Articles/784090/Conversion-Between-DataTable-and-List-TSource-in-C
        public static DataTable ToDataTable<TSource>(this IList<TSource> data)
        {
            DataTable dataTable = new DataTable(typeof(TSource).Name);
            PropertyInfo[] props = typeof(TSource).GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (PropertyInfo prop in props)
            {
                dataTable.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ??
                    prop.PropertyType);
            }

            foreach (TSource item in data)
            {
                var values = new object[props.Length];
                for (int i = 0; i < props.Length; i++)
                {
                    values[i] = props[i].GetValue(item, null);
                }
                dataTable.Rows.Add(values);
            }

            return dataTable;
        }

        /// <summary>
        /// 键排序列表
        /// </summary>
        /// <typeparam name="Key">键</typeparam>
        /// <typeparam name="Value">值</typeparam>
        /// <param name="dictionary">字典</param>
        /// <returns>键排序列表</returns>
        public static List<Key> SortedKeys<Key, Value>(this ConcurrentDictionary<Key, Value> dictionary)
        {
            if (dictionary == null) return null;

            List<Key> keys = dictionary.Keys.ToList();
            keys.Sort();
            return keys;
        }

        public static Dictionary<Key, Value> OrderByValueDesc<Key, Value>(this Dictionary<Key, Value> dictionary)
        {
            if (dictionary == null) return null;
            var result = from pair in dictionary orderby pair.Value descending select pair;
            return (Dictionary<Key, Value>)result;
        }

        public static Dictionary<Key, Value> OrderByValue<Key, Value>(this Dictionary<Key, Value> dictionary)
        {
            if (dictionary == null) return null;
            var result = from pair in dictionary orderby pair.Value select pair;
            return (Dictionary<Key, Value>)result;
        }

        public static Dictionary<Key, Value> OrderByKeyDesc<Key, Value>(this Dictionary<Key, Value> dictionary)
        {
            if (dictionary == null) return null;
            var result = from pair in dictionary orderby pair.Key descending select pair;
            return (Dictionary<Key, Value>)result;
        }

        public static Dictionary<Key, Value> OrderByKey<Key, Value>(this Dictionary<Key, Value> dictionary)
        {
            if (dictionary == null) return null;
            var result = from pair in dictionary orderby pair.Key select pair;
            return (Dictionary<Key, Value>)result;
        }

        public static ConcurrentDictionary<Key, Value> OrderByValueDesc<Key, Value>(this ConcurrentDictionary<Key, Value> dictionary)
        {
            if (dictionary == null) return null;
            var result = from pair in dictionary orderby pair.Value descending select pair;
            return (ConcurrentDictionary<Key, Value>)result;
        }

        public static ConcurrentDictionary<Key, Value> OrderByValue<Key, Value>(this ConcurrentDictionary<Key, Value> dictionary)
        {
            if (dictionary == null) return null;
            var result = from pair in dictionary orderby pair.Value select pair;
            return (ConcurrentDictionary<Key, Value>)result;
        }

        public static ConcurrentDictionary<Key, Value> OrderByKeyDesc<Key, Value>(this ConcurrentDictionary<Key, Value> dictionary)
        {
            if (dictionary == null) return null;
            var result = from pair in dictionary orderby pair.Key descending select pair;
            return (ConcurrentDictionary<Key, Value>)result;
        }

        public static ConcurrentDictionary<Key, Value> OrderByKey<Key, Value>(this ConcurrentDictionary<Key, Value> dictionary)
        {
            if (dictionary == null) return null;
            var result = from pair in dictionary orderby pair.Key select pair;
            return (ConcurrentDictionary<Key, Value>)result;
        }

        /// <summary>
        /// 随机变换List内容
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static IEnumerable<T> Randomize<T>(this IEnumerable<T> source)
        {
            Random r = new Random();
            var list = source.ToList();
            for (int i = 0; i < list.Count; i++)
                Swap(list, i, r.Next(list.Count));
            return list;
        }

        public static IEnumerable<T> RandomizeEx<T>(this IEnumerable<T> source)
        {
            Random r = new Random();
            return source.Select(x => new { Key = r.Next(), Value = x })
             .OrderBy(x => x.Key)
             .Select(x => x.Value);
        }

        public static void Swap<T>(List<T> list, int i, int j)
        {
            T tmp = list[i];
            list[i] = list[j];
            list[j] = tmp;
        }

        /// <summary>
        /// 循环列表执行事件
        /// studentList.Where(st => st.Age != 0)
        ///     .ForEach(st =>{ st.AgeInMonths = DateTime.Now.Subtract(st.DOB).TotalDays / 30); });
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="function"></param>
        public static void ForEach<T>(this IEnumerable<T> list, Action<T> function)
        {
            foreach (T item in list)
            {
                function(item);
            }
        }

        /// <summary>
        /// 键排序列表
        /// </summary>
        /// <typeparam name="Key">键</typeparam>
        /// <typeparam name="Value">值</typeparam>
        /// <param name="dictionary">字典</param>
        /// <returns>键排序列表</returns>
        public static List<Key> SortedKeys<Key, Value>(this Dictionary<Key, Value> dictionary)
        {
            if (dictionary == null) return null;

            List<Key> keys = dictionary.Keys.ToList();
            keys.Sort();
            return keys;
        }

        /// <summary>
        /// 键排序后，取值排序列表
        /// </summary>
        /// <typeparam name="Key">键</typeparam>
        /// <typeparam name="Value">值</typeparam>
        /// <param name="dictionary">字典</param>
        /// <returns>值排序列表</returns>
        public static List<Value> SortedValues<Key, Value>(this ConcurrentDictionary<Key, Value> dictionary)
        {
            if (dictionary == null) return null;

            List<Key> keys = dictionary.SortedKeys();
            List<Value> values = new List<Value>();
            foreach (var key in keys)
            {
                values.Add(dictionary[key]);
            }

            return values;
        }

        /// <summary>
        /// 键排序后，取值排序列表
        /// </summary>
        /// <typeparam name="Key">键</typeparam>
        /// <typeparam name="Value">值</typeparam>
        /// <param name="dictionary">字典</param>
        /// <returns>值排序列表</returns>
        public static List<Value> SortedValues<Key, Value>(this Dictionary<Key, Value> dictionary)
        {
            if (dictionary == null) return null;

            List<Key> keys = dictionary.SortedKeys();
            List<Value> values = new List<Value>();
            foreach (var key in keys)
            {
                values.Add(dictionary[key]);
            }

            return values;
        }

        /// <summary>
        /// 清除
        /// </summary>
        /// <typeparam name="T">T</typeparam>
        /// <param name="queue">queue</param>
        public static void Clear<T>(this ConcurrentQueue<T> queue)
        {
            while (queue.Count > 0)
            {
                queue.TryDequeue(out T _);
            }
        }

        public static bool NotContainsKey<Key, Value>(this ConcurrentDictionary<Key, Value> dictionary, Key key)
        {
            return !dictionary.ContainsKey(key);
        }

        public static bool NotContainsKey<Key, Value>(this Dictionary<Key, Value> dictionary, Key key)
        {
            return !dictionary.ContainsKey(key);
        }

        public static bool ContainsIndex(this IList list, int index)
        {
            if (list.IsNullOrEmpty()) return false;
            return index >= 0 && index < list.Count;
        }


        public static bool NotContainsIndex(this IList list, int index)
        {
            return !list.ContainsIndex(index);
        }

        public static T First<T>(this IList<T> list)
        {
            if (list == null || list.Count == 0) return default;
            return list[0];
        }

        public static T Last<T>(this IList<T> list)
        {
            if (list == null || list.Count == 0) return default;
            return list[list.Count - 1];
        }

        /// <summary>
        /// 增加或更新
        /// </summary>
        /// <param name="dictionary">字典</param>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <typeparam name="Key">键类型</typeparam>
        /// <typeparam name="Value">值类型</typeparam>
        public static void TryAddOrUpdate<Key, Value>(this ConcurrentDictionary<Key, Value> dictionary, Key key, Value value)
        {
            if (dictionary.ContainsKey(key))
            {
                dictionary[key] = value;
            }
            else
            {
                dictionary.TryAdd(key, value);
            }
        }

        /// <summary>
        /// 增加或更新
        /// </summary>
        /// <param name="dictionary">字典</param>
        /// <param name="key">键</param>
        /// <param name="value">值</param>
        /// <typeparam name="Key">键类型</typeparam>
        /// <typeparam name="Value">值类型</typeparam>
        public static void TryAddOrUpdate<Key, Value>(this Dictionary<Key, Value> dictionary, Key key, Value value)
        {
            if (dictionary.ContainsKey(key))
            {
                dictionary[key] = value;
            }
            else
            {
                dictionary.Add(key, value);
            }
        }

        /// <summary>
        /// GetOneByValue 从字典中找出第一个值与value相等的记录的key
        /// </summary>
        /// <typeparam name="TKey">键类型</typeparam>
        /// <typeparam name="TValue">值类型</typeparam>
        /// <param name="dic">字典</param>
        /// <param name="value">值</param>
        /// <returns>Key</returns>
        public static TKey FindFirstKeyByValue<TKey, TValue>(this IDictionary<TKey, TValue> dic, TValue value) where TKey : class where TValue : IEquatable<TValue>
        {
            foreach (var pair in dic)
            {
                if (pair.Value.Equals(value))
                {
                    return pair.Key;
                }
            }

            return default;
        }

        /// <summary>
        /// RemoveOneByValue 从字典中删除第一个值与value相等的记录
        /// </summary>
        /// <typeparam name="TKey">键类型</typeparam>
        /// <typeparam name="TValue">值类型</typeparam>
        /// <param name="dic">字典</param>
        /// <param name="value">值</param>
        public static void RemoveFirstValue<TKey, TValue>(this IDictionary<TKey, TValue> dic, TValue value) where TKey : class where TValue : IEquatable<TValue>
        {
            TKey dest = dic.FindFirstKeyByValue(value);
            if (dic.ContainsKey(dest))
            {
                dic.Remove(dest);
            }
        }

        /// <summary>
        /// Search 返回的是目标值所在的索引，如果不存在则返回-1
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="list">列表</param>
        /// <param name="value">值</param>
        /// <returns>索引</returns>
        public static int Search<T>(IList<T> list, T value) where T : IComparable
        {
            int left = 0;
            int right = list.Count;
            while (right >= left)
            {
                int middle = (left + right) / 2;
                if (list[middle].CompareTo(value) == 0)
                {
                    return middle;
                }

                if (list[middle].CompareTo(value) > 0)
                {
                    right = middle - 1;
                }
                else
                {
                    left = middle + 1;
                }
            }

            return -1;
        }

        /// <summary>
        /// 获取
        /// </summary>
        /// <param name="list">List</param>
        /// <param name="index">序号</param>
        /// <returns>值</returns>
        public static T Get<T>(this List<T> list, int index)
        {
            return list.Exist(index) ? list[index] : default;
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="list">List</param>
        /// <param name="index">序号</param>
        /// <param name="value">值</param>
        public static void Update<T>(this List<T> list, int index, T value)
        {
            if (!list.Exist(index))
            {
                return;
            }

            list[index] = value;
        }

        /// <summary>
        /// 索引是否存在
        /// </summary>
        /// <param name="list">List</param>
        /// <param name="index">序号</param>
        /// <returns>结果</returns>
        public static bool Exist<T>(this List<T> list, int index)
        {
            return (index >= 0 && index < list.Count);
        }

        /// <summary>
        /// 是否为空
        /// </summary>
        public static bool IsEmpty<T>(this List<T> list)
        {
            return list.Count == 0;
        }

        /// <summary>
        /// 第一个
        /// </summary>
        public static T First<T>(this List<T> list)
        {
            return list.Get(0);
        }

        /// <summary>
        /// 最后一个
        /// </summary>
        public static T Last<T>(this List<T> list)
        {
            return list.Get(list.Count - 1);
        }
    }
}